; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=arm -passes=typepromotion,verify  -S %s -o - | FileCheck %s

define zeroext i16 @overflow_add(i16 zeroext %a, i16 zeroext %b) {
; CHECK-LABEL: @overflow_add(
; CHECK-NEXT:    [[ADD:%.*]] = add i16 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[OR:%.*]] = or i16 [[ADD]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[OR]], 1024
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i16 2, i16 5
; CHECK-NEXT:    ret i16 [[RES]]
;
  %add = add i16 %a, %b
  %or = or i16 %add, 1
  %cmp = icmp ugt i16 %or, 1024
  %res = select i1 %cmp, i16 2, i16 5
  ret i16 %res
}

define zeroext i16 @overflow_sub(i16 zeroext %a, i16 zeroext %b) {
; CHECK-LABEL: @overflow_sub(
; CHECK-NEXT:    [[ADD:%.*]] = sub i16 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[OR:%.*]] = or i16 [[ADD]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[OR]], 1024
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i16 2, i16 5
; CHECK-NEXT:    ret i16 [[RES]]
;
  %add = sub i16 %a, %b
  %or = or i16 %add, 1
  %cmp = icmp ugt i16 %or, 1024
  %res = select i1 %cmp, i16 2, i16 5
  ret i16 %res
}

define zeroext i16 @overflow_mul(i16 zeroext %a, i16 zeroext %b) {
; CHECK-LABEL: @overflow_mul(
; CHECK-NEXT:    [[ADD:%.*]] = mul i16 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[OR:%.*]] = or i16 [[ADD]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[OR]], 1024
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i16 2, i16 5
; CHECK-NEXT:    ret i16 [[RES]]
;
  %add = mul i16 %a, %b
  %or = or i16 %add, 1
  %cmp = icmp ugt i16 %or, 1024
  %res = select i1 %cmp, i16 2, i16 5
  ret i16 %res
}

define zeroext i16 @overflow_shl(i16 zeroext %a, i16 zeroext %b) {
; CHECK-LABEL: @overflow_shl(
; CHECK-NEXT:    [[ADD:%.*]] = shl i16 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[OR:%.*]] = or i16 [[ADD]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[OR]], 1024
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i16 2, i16 5
; CHECK-NEXT:    ret i16 [[RES]]
;
  %add = shl i16 %a, %b
  %or = or i16 %add, 1
  %cmp = icmp ugt i16 %or, 1024
  %res = select i1 %cmp, i16 2, i16 5
  ret i16 %res
}

define i32 @overflow_add_no_consts(i8 zeroext %a, i8 zeroext %b, i8 zeroext %limit) {
; CHECK-LABEL: @overflow_add_no_consts(
; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[ADD]], [[LIMIT:%.*]]
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %add = add i8 %a, %b
  %cmp = icmp ugt i8 %add, %limit
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @overflow_add_const_limit(i8 zeroext %a, i8 zeroext %b) {
; CHECK-LABEL: @overflow_add_const_limit(
; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[ADD]], -128
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %add = add i8 %a, %b
  %cmp = icmp ugt i8 %add, 128
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @overflow_add_positive_const_limit(i8 zeroext %a) {
; CHECK-LABEL: @overflow_add_positive_const_limit(
; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[A:%.*]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[ADD]], -128
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %add = add i8 %a, 1
  %cmp = icmp ugt i8 %add, 128
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @unsafe_add_underflow(i8 zeroext %a) {
; CHECK-LABEL: @unsafe_add_underflow(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], -2
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[ADD]], -2
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %add = add i8 %a, -2
  %cmp = icmp ugt i8 %add, 254
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @safe_add_underflow(i8 zeroext %a) {
; CHECK-LABEL: @safe_add_underflow(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], -1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[ADD]], 254
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %add = add i8 %a, -1
  %cmp = icmp ugt i8 %add, 254
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @safe_add_underflow_neg(i8 zeroext %a) {
; CHECK-LABEL: @safe_add_underflow_neg(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP1]], -2
; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i32 [[ADD]], 250
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %add = add i8 %a, -2
  %cmp = icmp ule i8 %add, -6
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @overflow_sub_negative_const_limit(i8 zeroext %a) {
; CHECK-LABEL: @overflow_sub_negative_const_limit(
; CHECK-NEXT:    [[SUB:%.*]] = sub i8 [[A:%.*]], -1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SUB]], -128
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %sub = sub i8 %a, -1
  %cmp = icmp ugt i8 %sub, 128
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

; This is valid so long as the icmp immediate is sext.
define i32 @sext_sub_underflow(i8 zeroext %a) {
; CHECK-LABEL: @sext_sub_underflow(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[TMP1]], 6
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[SUB]], -6
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %sub = sub i8 %a, 6
  %cmp = icmp ugt i8 %sub, 250
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @safe_sub_underflow(i8 zeroext %a) {
; CHECK-LABEL: @safe_sub_underflow(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[TMP1]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i32 [[SUB]], 254
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %sub = sub i8 %a, 1
  %cmp = icmp ule i8 %sub, 254
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @safe_sub_underflow_neg(i8 zeroext %a) {
; CHECK-LABEL: @safe_sub_underflow_neg(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[TMP1]], 4
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[SUB]], 251
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %sub = sub i8 %a, 4
  %cmp = icmp uge i8 %sub, -5
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

; This is valid so long as the icmp immediate is sext.
define i32 @sext_sub_underflow_neg(i8 zeroext %a) {
; CHECK-LABEL: @sext_sub_underflow_neg(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[TMP1]], 4
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[SUB]], -3
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i32 8, i32 16
; CHECK-NEXT:    ret i32 [[RES]]
;
  %sub = sub i8 %a, 4
  %cmp = icmp ult i8 %sub, -3
  %res = select i1 %cmp, i32 8, i32 16
  ret i32 %res
}

define i32 @safe_sub_imm_var(ptr %b) {
; CHECK-LABEL: @safe_sub_imm_var(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B:%.*]], align 1
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[TMP0]] to i32
; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i32 248, [[TMP1]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[SUB]], 252
; CHECK-NEXT:    [[CONV4:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT:    ret i32 [[CONV4]]
;
entry:
  %0 = load i8, ptr %b, align 1
  %sub = sub nuw nsw i8 -8, %0
  %cmp = icmp ugt i8 %sub, 252
  %conv4 = zext i1 %cmp to i32
  ret i32 %conv4
}

define i32 @safe_sub_var_imm(ptr %b) {
; CHECK-LABEL: @safe_sub_var_imm(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B:%.*]], align 1
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[TMP0]] to i32
; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i32 [[TMP1]], 248
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[SUB]], 252
; CHECK-NEXT:    [[CONV4:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT:    ret i32 [[CONV4]]
;
entry:
  %0 = load i8, ptr %b, align 1
  %sub = sub nuw nsw i8 %0, -8
  %cmp = icmp ugt i8 %sub, 252
  %conv4 = zext i1 %cmp to i32
  ret i32 %conv4
}

define i32 @safe_add_imm_var(ptr %b) {
; CHECK-LABEL: @safe_add_imm_var(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B:%.*]], align 1
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[TMP0]] to i32
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 129, [[TMP1]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[ADD]], 127
; CHECK-NEXT:    [[CONV4:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT:    ret i32 [[CONV4]]
;
entry:
  %0 = load i8, ptr %b, align 1
  %add = add nuw nsw i8 -127, %0
  %cmp = icmp ugt i8 %add, 127
  %conv4 = zext i1 %cmp to i32
  ret i32 %conv4
}

define i32 @safe_add_var_imm(ptr %b) {
; CHECK-LABEL: @safe_add_var_imm(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[B:%.*]], align 1
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[TMP0]] to i32
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[TMP1]], 129
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[ADD]], 127
; CHECK-NEXT:    [[CONV4:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT:    ret i32 [[CONV4]]
;
entry:
  %0 = load i8, ptr %b, align 1
  %add = add nuw nsw i8 %0, -127
  %cmp = icmp ugt i8 %add, 127
  %conv4 = zext i1 %cmp to i32
  ret i32 %conv4
}

define i8 @convert_add_order(i8 zeroext %arg) {
; CHECK-LABEL: @convert_add_order(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[ARG:%.*]] to i32
; CHECK-NEXT:    [[MASK_0:%.*]] = and i32 [[TMP1]], 1
; CHECK-NEXT:    [[MASK_1:%.*]] = and i32 [[TMP1]], 2
; CHECK-NEXT:    [[SHL:%.*]] = or i32 [[TMP1]], 1
; CHECK-NEXT:    [[ADD:%.*]] = add nuw i32 [[SHL]], 10
; CHECK-NEXT:    [[CMP_0:%.*]] = icmp ult i32 [[ADD]], 60
; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[SHL]], -40
; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ult i32 [[SUB]], 20
; CHECK-NEXT:    [[MASK_SEL:%.*]] = select i1 [[CMP_1]], i32 [[MASK_0]], i32 [[MASK_1]]
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP_0]], i32 [[MASK_SEL]], i32 [[TMP1]]
; CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[RES]] to i8
; CHECK-NEXT:    ret i8 [[TMP2]]
;
  %mask.0 = and i8 %arg, 1
  %mask.1 = and i8 %arg, 2
  %shl = or i8 %arg, 1
  %add = add nuw i8 %shl, 10
  %cmp.0 = icmp ult i8 %add, 60
  %sub = add nsw i8 %shl, -40
  %cmp.1 = icmp ult i8 %sub, 20
  %mask.sel = select i1 %cmp.1, i8 %mask.0, i8 %mask.1
  %res = select i1 %cmp.0, i8 %mask.sel, i8 %arg
  ret i8 %res
}

define i8 @underflow_if_sub(i32 %arg, i8 zeroext %arg1) {
; CHECK-LABEL: @underflow_if_sub(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[ARG1:%.*]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[ARG:%.*]], 0
; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[ARG]], [[CONV]]
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i32 [[AND]] to i8
; CHECK-NEXT:    [[TMP2:%.*]] = zext i8 [[TRUNC]] to i32
; CHECK-NEXT:    [[CONV1:%.*]] = add nuw nsw i32 [[TMP2]], 245
; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ult i32 [[CONV1]], [[TMP1]]
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP_1]], i32 [[CONV1]], i32 100
; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[RES]] to i8
; CHECK-NEXT:    ret i8 [[TMP3]]
;
  %cmp = icmp sgt i32 %arg, 0
  %conv = zext i1 %cmp to i32
  %and = and i32 %arg, %conv
  %trunc = trunc i32 %and to i8
  %conv1 = add nuw nsw i8 %trunc, -11
  %cmp.1 = icmp ult i8 %conv1, %arg1
  %res = select i1 %cmp.1, i8 %conv1, i8 100
  ret i8 %res
}

define i8 @underflow_if_sub_signext(i32 %arg, i8 signext %arg1) {
; CHECK-LABEL: @underflow_if_sub_signext(
; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[ARG1:%.*]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[ARG:%.*]], 0
; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[ARG]], [[CONV]]
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i32 [[AND]] to i8
; CHECK-NEXT:    [[TMP2:%.*]] = zext i8 [[TRUNC]] to i32
; CHECK-NEXT:    [[CONV1:%.*]] = add nuw nsw i32 [[TMP2]], 245
; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ugt i32 [[TMP1]], [[CONV1]]
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP_1]], i32 [[CONV1]], i32 100
; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[RES]] to i8
; CHECK-NEXT:    ret i8 [[TMP3]]
;
  %cmp = icmp sgt i32 %arg, 0
  %conv = zext i1 %cmp to i32
  %and = and i32 %arg, %conv
  %trunc = trunc i32 %and to i8
  %conv1 = add nuw nsw i8 %trunc, -11
  %cmp.1 = icmp ugt i8 %arg1, %conv1
  %res = select i1 %cmp.1, i8 %conv1, i8 100
  ret i8 %res
}
